package bigapps.myneighbor.service.impl;

import bigapps.myneighbor.domain.ParkingFacilityList;
import bigapps.myneighbor.domain.ParkingFacility;
import bigapps.myneighbor.service.ParkingFacilityService;
import bigapps.myneighbor.dao.ParkingFacilityDao;
import bigapps.myneighbor.dao.StageDao;
import bigapps.myneighbor.exception.MyNeighborException;
import bigapps.myneighbor.util.LatitudeLongitudeUtil;

import org.apache.commons.csv.CSVParser;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;

import com.google.appengine.api.datastore.Blob;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.List;

@Service(value = "parkingFacilityService")
public class ParkingFacilityServiceImpl implements ParkingFacilityService {
	@Autowired
	private ParkingFacilityDao parkingFacilityDao;
	@Autowired
	private StageDao stageDao;

	Logger logger = Logger.getLogger(ParkingFacilityServiceImpl.class);

	public ParkingFacilityList getParkingFacilityList(Double latitude,
			Double longitude) {
		List<ParkingFacility> listParkingFacility = parkingFacilityDao
		.findByClosestDistance(latitude, longitude);
		ParkingFacilityList parkingFacilityList = new ParkingFacilityList();
		parkingFacilityList.parkingFacilityList = listParkingFacility;
		return parkingFacilityList;
	}

	//	@Transactional(propagation = Propagation.REQUIRES_NEW)
	//	@Transactional
	public void create(String line[]) {
		ParkingFacility parkingFacility = new ParkingFacility();
		parkingFacility.setFacilityType(line[0]);
		parkingFacility.setLicenseNumber(line[1]);
		parkingFacility.setEntityName(line[2]);
		parkingFacility.setCamisTradeName(line[3]);
		parkingFacility.setAddressBuilding(line[4]);
		parkingFacility.setAddressStreetName(line[5]);
		parkingFacility.setAddressLocation(line[6]);
		parkingFacility.setAddressCity(line[7]);
		parkingFacility.setAddressState(line[8]);
		parkingFacility.setAddressZipCode(line[9]);
		parkingFacility.setTelephoneNumber(line[10]);
		parkingFacility.setNumberOfSpaces(line[11]);
		parkingFacility.setStatus(new Integer(0));
		if(parkingFacilityDao.findEntity(parkingFacility) == null)
		{
			parkingFacilityDao.save(parkingFacility);
			logger.info("entity created");
		}
		else
		{
			logger.info("entity not created (already exists)");
		}
	}

	private void updateLatitudeLongitude(boolean repair){
		int numSuccess = 0;
		int numFail = 0;
		List<ParkingFacility> listOfParkingFacility;
		if(!repair)
		{
			logger.info("New");
			listOfParkingFacility = parkingFacilityDao
			.getUnassignedLatitudeLongitude();
		}
		else
		{
			logger.info("Repair");
			listOfParkingFacility = parkingFacilityDao
			.getErroredLatitudeLongitude();
		}
		for (ParkingFacility pf : listOfParkingFacility) {
			try {
				double f[] = LatitudeLongitudeUtil.getLatitudeLongitude(pf
						.getAddressBuilding()
						+ " "
						+ pf.getAddressStreetName()
						+ ","
						+ pf.getAddressCity()
						+ ","
						+ pf.getAddressState()
						+ "," + pf.getAddressZipCode());
				parkingFacilityDao.updateLatitudeLongitude(pf, 1, f[0], f[1]);
				numSuccess++;
			} catch(MyNeighborException mne){
				numFail++;
				logger.info("ID: " + pf.getEntityId()
						+ " failed to assign latitude and longitude (Error: " + mne.getMessage() + ")");
				if(!repair)
				{
					parkingFacilityDao.updateLatitudeLongitude(pf, 2, null, null);
				}
				else
				{
					parkingFacilityDao.updateLatitudeLongitude(pf, pf.getStatus() + 1, null, null);
				}
			}
			catch (Exception e) {
				numFail++;
				logger.info("ID: " + pf.getEntityId()
						+ " failed to assign latitude and longitude");
				e.printStackTrace();
				if(!repair)
				{
					parkingFacilityDao.updateLatitudeLongitude(pf, 2, null, null);
				}
				else
				{
					parkingFacilityDao.updateLatitudeLongitude(pf, pf.getStatus() + 1, null, null);
				}
			}
		}
		logger.info("Number of reocrd succeeded: " + numSuccess);
		logger.info("Number of record failed: " + numFail);
	}
	public void updateLatitudeLongitude() {
		updateLatitudeLongitude(false);
	}

	public void repairLatitudeLongitude() {
		updateLatitudeLongitude(true);
		/*
		List<ParkingFacility> listOfParkingFacility = parkingFacilityDao
				.getErroredLatitudeLongitude();
		int numSuccess = 0;
		int numFail = 0;

		for (ParkingFacility pf : listOfParkingFacility) {
			try {
				float f[] = LatitudeLongitudeUtil.getLatitudeLongitude(pf
						.getAddressBuilding()
						+ " "
						+ pf.getAddressStreetName()
						+ ","
						+ pf.getAddressCity()
						+ ","
						+ pf.getAddressState()
						+ "," + pf.getAddressZipCode());
				parkingFacilityDao.updateLatitudeLongitude(pf, 1, f[0], f[1]);
				numSuccess++;
			} catch (Exception e) {
				numFail++;
				System.out.println("ID: " + pf.getEntityId()
						+ " failed to assign latitude and longitude");
				e.printStackTrace();
				parkingFacilityDao.updateLatitudeLongitude(pf, pf.getStatus() + 1, null, null);
			}
		}

		System.out.println("Number of reocrd succeeded: " + numSuccess);
		System.out.println("Number of record failed: " + numFail);
		 */
	}
	//	@Transactional
	public void updateData() {
		int numProcessed = 0;
		System.out.println("ParkingFacilityService.updateData called");
		try {
			Blob blob = stageDao.getParkingFacility();
			byte[] b = blob.getBytes();
			System.out.println("content from the database: " + new String(b));
			ByteArrayInputStream stream = new ByteArrayInputStream(b);

			BufferedReader reader = new BufferedReader(new InputStreamReader(
					stream));
			CSVParser parser = new CSVParser(reader);
			String line[] = null;
			if ((line = parser.getLine()) != null) {
				while ((line = parser.getLine()) != null) {
					for (int i = 1; i < line.length; i++) {
						System.out.println(line[i]);
					}
					try {
						create(line);
						numProcessed++;
					} catch (Exception e) {
						System.out.println(line[1]
						                        + " failed to get latitude and longitude");
						e.printStackTrace();
					}
				}
				reader.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			logger.info("Number of record processed: " + numProcessed);
		}
	}
	public String getStatus(){
		String statusStr;
		List<ParkingFacility> list1 = parkingFacilityDao.findByStatus(0);
		List<ParkingFacility> list2 = parkingFacilityDao.findByStatus(1);
		List<ParkingFacility> list3 = parkingFacilityDao.findByStatus(2);

		int num1 = list1.size();
		int num2 = list2.size();
		int num3 = list3.size();

		logger.info("Number of status = 0: " + num1);
		logger.info("Number of status = 1: " + num2);
		logger.info("Number of status > 2: " + num3);

		try{
			statusStr = "Number of status = 0 (LATITUDE & LONGITUDE UNPROCESSED): " + num1 + "<BR>Number of status = 1(LATITUDE & LONGITUDE PROCESSED): " + num2 + "<BR>Number of status > 2(ERROR): " + num3;
		}
		catch(Exception e)
		{
			statusStr = "Exception occurred!";
			e.printStackTrace();
		}
		return statusStr;
	}
}
